package com.ray.export.spring;

import com.ray.export.exception.DataRunnerException;
import com.ray.export.strategy.result.SuccessResult;
import com.ray.export.template.actuator.Actuator;
import com.ray.export.template.actuator.ActuatorFactory;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.lang.annotation.Annotation;

/**
 * @author bo shen
 * @Description: 导入导出切面
 * @Class: ImportExportAspect
 * @Package com.ray.spring
 * @date 2019/11/21 9:18
 * @company <p>杭州传化陆鲸科技有限公司</p>
 * @updateRecord time(修改时间)  author(修改人)   desc(修改内容)
 */
@Aspect
@Slf4j
public class ImportExportAspect implements ApplicationContextAware {

    @Autowired(required = false)
    private PlatformTransactionManager platformTransactionManager;

    @Autowired(required = false)
    private TransactionDefinition transactionDefinition;

    /**
     * 拦截切面 拦截 所有导入导出支持的模板注释
     * 导入导出组件 所有支持的模板注释 定义在com.ray.template下面
     *
     * @see com.ray.export.template.ImportTemplate
     */
    @Pointcut("@annotation(com.ray.export.template.SyncImportTemplate)")
    public void syncImportTemplate() {
    }

    @Pointcut("@annotation(com.ray.export.template.ImportTemplate)")
    public void importTemplate() {
    }

    @Pointcut("@annotation(com.ray.export.template.ConfirmImportTemplate)")
    public void confirmImportTemplate() {
    }

    @Pointcut("@annotation(com.ray.export.template.ExportTemplate)")
    public void exportTemplate() {
    }


    @Around("syncImportTemplate() || importTemplate() || exportTemplate() || confirmImportTemplate()")
    @Transactional
    public Object dispath(ProceedingJoinPoint pjp) {
        //获取方法注释
        Annotation[] annotations = ((MethodSignature) pjp.getSignature()).getMethod().getAnnotations();
        //获取第一个付个的注解
        Annotation annotation = loadAnnotations(annotations);
        Actuator actuator = ActuatorFactory.getActuator(annotation.annotationType());
        //获取的参数
        Object[] args = pjp.getArgs();
        TransactionStatus transaction = null;
        //在有事务管理的情况下
        //开始事务配置
        if (!ObjectUtils.isEmpty(platformTransactionManager)) {
            log.info("任务开启事务");
            // 获得事务状态
            transaction = platformTransactionManager.getTransaction(transactionDefinition);
        }
        try {
            Object object = actuator.run(annotation, args);
            if (!ObjectUtils.isEmpty(platformTransactionManager)) {
                platformTransactionManager.commit(transaction);
            }
            return object;
        }catch (DataRunnerException e) {
            //手动事务回滚
            if (!ObjectUtils.isEmpty(platformTransactionManager)) {
                platformTransactionManager.rollback(transaction);
            }
            return new SuccessResult(false,e.getObject(), e.getMessage());
        } catch (Exception e) {
            //手动事务回滚
            if (!ObjectUtils.isEmpty(platformTransactionManager)) {
                platformTransactionManager.rollback(transaction);
            }
            return new SuccessResult(false, e.getMessage());
        }
    }

    /**
     * @param annotations
     * @return
     */
    private Annotation loadAnnotations(Annotation[] annotations) {
        for (Annotation annotation : annotations) {
            if (ActuatorFactory.isSupport(annotation.annotationType())) {
                return annotation;
            }
        }
        throw new RuntimeException("不支持的注解");
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("导入导出切面被加载成功.");
    }
}
